package com.yupi.yupicturebackend.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.yupi.yupicturebackend.model.dto.picture.WatermarkConfig;
import com.yupi.yupicturebackend.model.dto.picture.CopyrightInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * 图片水印和版权保护工具类
 * 
 * <p>提供智能水印添加、版权信息嵌入、盗图检测等功能</p>
 * 
 * @author yupi
 */
@Slf4j
@Component
public class PictureWatermarkUtils {

    /**
     * 添加文字水印
     *
     * @param originalImageUrl 原图URL
     * @param watermarkConfig 水印配置
     * @return 添加水印后的图片字节数组
     */
    public static byte[] addTextWatermark(String originalImageUrl, WatermarkConfig watermarkConfig) {
        try {
            BufferedImage originalImage = ImageIO.read(new URL(originalImageUrl));
            return addTextWatermark(originalImage, watermarkConfig);
        } catch (IOException e) {
            log.error("读取原图失败: {}", originalImageUrl, e);
            return null;
        }
    }

    /**
     * 添加文字水印
     *
     * @param originalImage 原图
     * @param watermarkConfig 水印配置
     * @return 添加水印后的图片字节数组
     */
    public static byte[] addTextWatermark(BufferedImage originalImage, WatermarkConfig watermarkConfig) {
        try {
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();
            
            BufferedImage watermarkedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = watermarkedImage.createGraphics();
            
            // 绘制原图
            g2d.drawImage(originalImage, 0, 0, null);
            
            // 设置水印样式
            setupWatermarkStyle(g2d, watermarkConfig, width, height);
            
            // 计算水印位置
            Point watermarkPosition = calculateWatermarkPosition(width, height, watermarkConfig);
            
            // 绘制水印文字
            g2d.drawString(watermarkConfig.getText(), watermarkPosition.x, watermarkPosition.y);
            g2d.dispose();
            
            // 转换为字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(watermarkedImage, "PNG", baos);
            return baos.toByteArray();
            
        } catch (Exception e) {
            log.error("添加文字水印失败", e);
            return null;
        }
    }

    /**
     * 添加图片水印
     *
     * @param originalImageUrl 原图URL
     * @param watermarkImageUrl 水印图片URL
     * @param watermarkConfig 水印配置
     * @return 添加水印后的图片字节数组
     */
    public static byte[] addImageWatermark(String originalImageUrl, String watermarkImageUrl, WatermarkConfig watermarkConfig) {
        try {
            BufferedImage originalImage = ImageIO.read(new URL(originalImageUrl));
            BufferedImage watermarkImage = ImageIO.read(new URL(watermarkImageUrl));
            return addImageWatermark(originalImage, watermarkImage, watermarkConfig);
        } catch (IOException e) {
            log.error("读取图片失败: {} 或 {}", originalImageUrl, watermarkImageUrl, e);
            return null;
        }
    }

    /**
     * 添加图片水印
     *
     * @param originalImage 原图
     * @param watermarkImage 水印图片
     * @param watermarkConfig 水印配置
     * @return 添加水印后的图片字节数组
     */
    public static byte[] addImageWatermark(BufferedImage originalImage, BufferedImage watermarkImage, WatermarkConfig watermarkConfig) {
        try {
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();
            
            BufferedImage watermarkedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = watermarkedImage.createGraphics();
            
            // 绘制原图
            g2d.drawImage(originalImage, 0, 0, null);
            
            // 设置透明度
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, watermarkConfig.getOpacity()));
            
            // 计算水印图片大小和位置
            int watermarkWidth = (int) (width * watermarkConfig.getScale());
            int watermarkHeight = (int) (watermarkImage.getHeight() * watermarkWidth / watermarkImage.getWidth());
            
            Point watermarkPosition = calculateWatermarkPosition(width, height, watermarkConfig);
            
            // 绘制水印图片
            g2d.drawImage(watermarkImage, watermarkPosition.x, watermarkPosition.y, watermarkWidth, watermarkHeight, null);
            g2d.dispose();
            
            // 转换为字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(watermarkedImage, "PNG", baos);
            return baos.toByteArray();
            
        } catch (Exception e) {
            log.error("添加图片水印失败", e);
            return null;
        }
    }

    /**
     * 添加隐形水印（数字水印）
     *
     * @param originalImageUrl 原图URL
     * @param copyrightInfo 版权信息
     * @return 添加隐形水印后的图片字节数组
     */
    public static byte[] addInvisibleWatermark(String originalImageUrl, CopyrightInfo copyrightInfo) {
        try {
            BufferedImage originalImage = ImageIO.read(new URL(originalImageUrl));
            return addInvisibleWatermark(originalImage, copyrightInfo);
        } catch (IOException e) {
            log.error("读取原图失败: {}", originalImageUrl, e);
            return null;
        }
    }

    /**
     * 添加隐形水印（LSB算法）
     *
     * @param originalImage 原图
     * @param copyrightInfo 版权信息
     * @return 添加隐形水印后的图片字节数组
     */
    public static byte[] addInvisibleWatermark(BufferedImage originalImage, CopyrightInfo copyrightInfo) {
        try {
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();
            
            BufferedImage watermarkedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            
            // 将版权信息转换为二进制字符串
            String copyrightData = copyrightInfo.toString();
            String binaryData = stringToBinary(copyrightData);
            
            int dataIndex = 0;
            for (int y = 0; y < height && dataIndex < binaryData.length(); y++) {
                for (int x = 0; x < width && dataIndex < binaryData.length(); x++) {
                    int rgb = originalImage.getRGB(x, y);
                    
                    // 提取RGB分量
                    int red = (rgb >> 16) & 0xFF;
                    int green = (rgb >> 8) & 0xFF;
                    int blue = rgb & 0xFF;
                    
                    // 修改蓝色分量的最低位
                    if (dataIndex < binaryData.length()) {
                        blue = (blue & 0xFE) | Character.getNumericValue(binaryData.charAt(dataIndex));
                        dataIndex++;
                    }
                    
                    // 重新组合RGB
                    int newRgb = (red << 16) | (green << 8) | blue;
                    watermarkedImage.setRGB(x, y, newRgb);
                }
            }
            
            // 转换为字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(watermarkedImage, "PNG", baos);
            return baos.toByteArray();
            
        } catch (Exception e) {
            log.error("添加隐形水印失败", e);
            return null;
        }
    }

    /**
     * 提取隐形水印
     *
     * @param watermarkedImageUrl 含水印图片URL
     * @param dataLength 数据长度
     * @return 提取的版权信息
     */
    public static String extractInvisibleWatermark(String watermarkedImageUrl, int dataLength) {
        try {
            BufferedImage watermarkedImage = ImageIO.read(new URL(watermarkedImageUrl));
            return extractInvisibleWatermark(watermarkedImage, dataLength);
        } catch (IOException e) {
            log.error("读取含水印图片失败: {}", watermarkedImageUrl, e);
            return null;
        }
    }

    /**
     * 提取隐形水印
     *
     * @param watermarkedImage 含水印图片
     * @param dataLength 数据长度
     * @return 提取的版权信息
     */
    public static String extractInvisibleWatermark(BufferedImage watermarkedImage, int dataLength) {
        try {
            int width = watermarkedImage.getWidth();
            int height = watermarkedImage.getHeight();
            
            StringBuilder binaryData = new StringBuilder();
            int extractedBits = 0;
            
            for (int y = 0; y < height && extractedBits < dataLength * 8; y++) {
                for (int x = 0; x < width && extractedBits < dataLength * 8; x++) {
                    int rgb = watermarkedImage.getRGB(x, y);
                    int blue = rgb & 0xFF;
                    
                    // 提取蓝色分量的最低位
                    binaryData.append(blue & 1);
                    extractedBits++;
                }
            }
            
            // 将二进制字符串转换为文本
            return binaryToString(binaryData.toString());
            
        } catch (Exception e) {
            log.error("提取隐形水印失败", e);
            return null;
        }
    }

    /**
     * 生成图片指纹
     *
     * @param imageUrl 图片URL
     * @return 图片指纹
     */
    public static String generateImageFingerprint(String imageUrl) {
        try {
            BufferedImage image = ImageIO.read(new URL(imageUrl));
            return generateImageFingerprint(image);
        } catch (IOException e) {
            log.error("读取图片失败: {}", imageUrl, e);
            return null;
        }
    }

    /**
     * 生成图片指纹（基于感知哈希）
     *
     * @param image 图片
     * @return 图片指纹
     */
    public static String generateImageFingerprint(BufferedImage image) {
        try {
            // 缩放到8x8
            BufferedImage resized = new BufferedImage(8, 8, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = resized.createGraphics();
            g2d.drawImage(image, 0, 0, 8, 8, null);
            g2d.dispose();
            
            // 转换为灰度并计算平均值
            int[] grayValues = new int[64];
            int sum = 0;
            
            for (int y = 0; y < 8; y++) {
                for (int x = 0; x < 8; x++) {
                    int rgb = resized.getRGB(x, y);
                    int gray = (int) (0.299 * ((rgb >> 16) & 0xFF) + 0.587 * ((rgb >> 8) & 0xFF) + 0.114 * (rgb & 0xFF));
                    grayValues[y * 8 + x] = gray;
                    sum += gray;
                }
            }
            
            int average = sum / 64;
            
            // 生成哈希
            StringBuilder hash = new StringBuilder();
            for (int grayValue : grayValues) {
                hash.append(grayValue >= average ? "1" : "0");
            }
            
            return hash.toString();
            
        } catch (Exception e) {
            log.error("生成图片指纹失败", e);
            return null;
        }
    }

    /**
     * 检测图片是否被盗用
     *
     * @param originalFingerprint 原图指纹
     * @param suspiciousImageUrl 疑似盗图URL
     * @return 是否为盗图
     */
    public static boolean detectImageTheft(String originalFingerprint, String suspiciousImageUrl) {
        String suspiciousFingerprint = generateImageFingerprint(suspiciousImageUrl);
        if (suspiciousFingerprint == null) {
            return false;
        }
        
        // 计算汉明距离
        int hammingDistance = calculateHammingDistance(originalFingerprint, suspiciousFingerprint);
        
        // 汉明距离小于5认为是相似图片
        return hammingDistance < 5;
    }

    /**
     * 批量添加水印
     *
     * @param imageUrls 图片URL列表
     * @param watermarkConfig 水印配置
     * @return 处理结果映射
     */
    public static Map<String, byte[]> batchAddWatermark(String[] imageUrls, WatermarkConfig watermarkConfig) {
        Map<String, byte[]> results = new HashMap<>();
        
        for (String imageUrl : imageUrls) {
            try {
                byte[] watermarkedImage = addTextWatermark(imageUrl, watermarkConfig);
                if (watermarkedImage != null) {
                    results.put(imageUrl, watermarkedImage);
                }
            } catch (Exception e) {
                log.error("批量添加水印失败: {}", imageUrl, e);
            }
        }
        
        return results;
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 设置水印样式
     */
    private static void setupWatermarkStyle(Graphics2D g2d, WatermarkConfig config, int imageWidth, int imageHeight) {
        // 设置抗锯齿
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        // 设置字体
        int fontSize = (int) (Math.min(imageWidth, imageHeight) * config.getFontSizeRatio());
        Font font = new Font(config.getFontFamily(), Font.BOLD, fontSize);
        g2d.setFont(font);
        
        // 设置颜色和透明度
        Color color = Color.decode(config.getColor());
        g2d.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) (255 * config.getOpacity())));
        
        // 设置旋转角度
        if (config.getRotation() != 0) {
            g2d.rotate(Math.toRadians(config.getRotation()), imageWidth / 2.0, imageHeight / 2.0);
        }
    }

    /**
     * 计算水印位置
     */
    private static Point calculateWatermarkPosition(int imageWidth, int imageHeight, WatermarkConfig config) {
        int x, y;
        
        switch (config.getPosition().toLowerCase()) {
            case "top-left":
                x = config.getMargin();
                y = config.getMargin();
                break;
            case "top-right":
                x = imageWidth - config.getMargin();
                y = config.getMargin();
                break;
            case "bottom-left":
                x = config.getMargin();
                y = imageHeight - config.getMargin();
                break;
            case "bottom-right":
                x = imageWidth - config.getMargin();
                y = imageHeight - config.getMargin();
                break;
            case "center":
            default:
                x = imageWidth / 2;
                y = imageHeight / 2;
                break;
        }
        
        return new Point(x, y);
    }

    /**
     * 字符串转二进制
     */
    private static String stringToBinary(String text) {
        StringBuilder binary = new StringBuilder();
        for (char c : text.toCharArray()) {
            binary.append(String.format("%8s", Integer.toBinaryString(c)).replace(' ', '0'));
        }
        return binary.toString();
    }

    /**
     * 二进制转字符串
     */
    private static String binaryToString(String binary) {
        StringBuilder text = new StringBuilder();
        for (int i = 0; i < binary.length(); i += 8) {
            if (i + 8 <= binary.length()) {
                String byteString = binary.substring(i, i + 8);
                int charCode = Integer.parseInt(byteString, 2);
                if (charCode > 0) {
                    text.append((char) charCode);
                }
            }
        }
        return text.toString();
    }

    /**
     * 计算汉明距离
     */
    private static int calculateHammingDistance(String hash1, String hash2) {
        if (hash1.length() != hash2.length()) {
            return Integer.MAX_VALUE;
        }
        
        int distance = 0;
        for (int i = 0; i < hash1.length(); i++) {
            if (hash1.charAt(i) != hash2.charAt(i)) {
                distance++;
            }
        }
        return distance;
    }
}
